using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace Acms.Bll
{
    public abstract class BaseItem
    {
        protected BaseItem()
        {
            isNewRecord = true;
        }

        protected BaseItem(Hashtable table)
        {
            Load(table);
            concurencyId = LoadConcurencyId(table);
        }

        protected BaseItem(Hashtable table, ICollection collection)
        {
            Load(table);
            concurencyId = LoadConcurencyId(table);
            this.collection = collection;
        }

        protected abstract void Load(Hashtable table);

        private ICollection collection;

        private object concurencyId;
        public object ConcurencyId
        {
            get { return concurencyId; }
        }

        protected void SetVersionId(object newVersionId)
        {
            concurencyId = newVersionId;
        }

        private bool isNewRecord;
        protected bool IsNewRecord
        {
            get { return isNewRecord; }
        }

        protected void Updated(object versionId)
        {
            this.isNewRecord = false;
            this.concurencyId = versionId;
        }

        protected void Deleted()
        {
        }

        private Guid transactionKey;
        public Guid TransactionKey
        {
            get { return transactionKey; }
        }

        public void UseTransaction(Guid key)
        {
            transactionKey = key;
        }

        public void BeginTransaction()
        {
            if (transactionKey != Guid.Empty)
            {
                throw new ApplicationException("This class is already using a transaction");
            }
            else
            {
                transactionKey = CreateDal().StartTransaction();
            }
        }

        public void CommitTransaction()
        {
            if (transactionKey == Guid.Empty)
            {
                throw new ApplicationException("This class is not using a transaction");
            }
            else
            {
                CreateDal().CommitTransaction(transactionKey);
            }
        }

        public void RollbackTransaction()
        {
            if (transactionKey == Guid.Empty)
            {
                throw new ApplicationException("This class is not using a transaction");
            }
            else
            {
                CreateDal().RollbackTransaction(transactionKey);
            }
        }

        protected abstract Acms.SqlDal.Base CreateDal();

        protected virtual void SaveChanges(ref object concurencyId, SqlDal.Base dal)
        {
            throw new NotImplementedException("Method Save Changes must be overriden if Update is called");
        }

        protected void Update()
        {
            SqlDal.Base dal = CreateDal();
            if (TransactionKey != Guid.Empty)
            {
                dal.UseTransaction(TransactionKey);
            }
            SaveChanges(ref concurencyId, dal);
            Updated(ConcurencyId);
        }

        protected virtual void DeleteRecord(object concurencyId, SqlDal.Base dal)
        {
            throw new NotImplementedException("Method DeleteRecord must be overriden if Delete is called");
        }

        protected void Delete()
        {
            SqlDal.Base dal = CreateDal();
            if (TransactionKey != Guid.Empty)
            {
                dal.UseTransaction(TransactionKey);
            }
            DeleteRecord(ConcurencyId, dal);
            Deleted();
        }

        public bool CheckConcurent(object concurencyId)
        {
            bool isConcurrent = false;
            if (this.ConcurencyId == null && concurencyId == null)
            {
                isConcurrent = true;
            }
            else if ((this.ConcurencyId == null && concurencyId != null) || (this.ConcurencyId != null && concurencyId == null))
            {
                isConcurrent = false;
            }
            else
            {
                isConcurrent = this.ConcurencyId.Equals(concurencyId);
            }
            return isConcurrent;
        }

        protected object LoadConcurencyId(Hashtable table)
        {
            if (table.ContainsKey(SqlDal.Base.BaseFields.VersionId))
            {
                return table[SqlDal.Base.BaseFields.VersionId];
            }
            else
            {
                return null;
            }
        }
    }
}
